<script setup lang="ts">
import { ref } from "vue";
// https://plus-pro-components.com/components/form.html
import "plus-pro-components/es/components/form/style/css";
import { FormProps } from "../utils/types";
import {
  type PlusColumn,
  type FieldValues,
  PlusForm
} from "plus-pro-components";

import { h, Fragment } from "vue";

/**
 * @plus-pro-components/utils 是辅助plus-pro-components的工具包，如果需要使用，需要单独安装
 * 参考文档 https://plus-pro-components.com/api/utils/
 */
import { fileToDataURL } from "@plus-pro-components/utils";
import { ElUpload, ElButton, ElImage, ElProgress } from "element-plus";

import Progress1 from "./progress1.vue";
import {
  checkfile,
  checkChunkFile,
  uploadchunk,
  uploadImg,
  mergechunks
} from "@/api/bxj/media";
import { saveOrUpdateMovie } from "@/api/bxj/movie";
import { message } from "@/utils/message";
import { md5 } from "js-md5"; // 导入 MD5 库
const uploadRef = ref(true);
const state = ref<FieldValues>({
  desc: "",
  name: "",
  object: "",
  quarter: "",
  status: 1,
  img: "",
  imgMd5: "",
  videoMd5: "",
  video: ""
});
const rules = {
  name: [
    {
      required: true,
      message: "请输入名称"
    }
  ],
  object: [
    {
      required: true,
      message: "请输入主人公"
    }
  ],
  quarter: [
    {
      required: true,
      message: "请选择档期"
    }
  ],
  desc: [
    {
      required: true,
      message: "请输入电影描述"
    }
  ]
};
interface TreeItem {
  id: string;
  name: string;
  parentId?: string; // 如果有父节点
}

interface CascaderItem {
  value: string;
  label: string;
  children?: CascaderItem[]; // 子节点
}

const percentage = ref(0);
//分块总数
const totalChunks = ref(0);
//视频名字
const fileName = ref(null);
const props = withDefaults(defineProps<FormProps>(), {
  formInline: () => ({
    id: "",
    title: "新增",
    higherDeptOptions: [],
    name: "",
    object: "",
    quarterId: "",
    status: 0,
    img: "",
    imgMd5: "",
    videoMd5: "",
    video: "",
    desc: ""
  })
});
const newFormInline = ref(props.formInline);
const quarters = ref(props.formInline.higherDeptOptions);
Object.assign(state, newFormInline);

const columns: PlusColumn[] = [
  {
    label: "名称",
    width: 120,
    prop: "name",
    valueType: "copy",
    tooltip: "电影名称"
  },
  {
    label: "演员",
    width: 120,
    prop: "object",
    valueType: "copy",
    tooltip: "填写演员"
  },
  {
    label: "档期",
    width: 120,
    prop: "quarter",
    valueType: "cascader",
    options: quarters,
    tooltip: "我是名称"
  },
  {
    label: "状态",
    width: 120,
    prop: "status",
    valueType: "select",
    options: [
      {
        label: "上架",
        value: "1",
        color: "red"
      },
      {
        label: "下架",
        value: "0",
        color: "blue"
      }
    ]
  },
  {
    label: "封面",
    prop: "img",
    width: 100,
    valueType: "img",
    renderField(value, onChange) {
      // 自定义上传
      const handleHttpRequest = async ({ file, onError, onSuccess }: any) => {
        try {
          await uploadImg(file);
          const fileMd5 = await calculateFileMd5(file);
          // 将计算出的 MD5 值赋值给 state.imgMd5
          state.value.imgMd5 = fileMd5;
        } catch (error: any) {}
        return file;
      };

      return h(Fragment, [
        h(ElImage as any, {
          src: value,
          previewSrcList: [value],
          style: value
            ? {
                marginRight: "10px"
              }
            : { display: "none" }
        }),
        h(
          ElUpload,
          {
            action: "",
            limit: 1, // 限制上传文件数量为 1
            httpRequest: handleHttpRequest,
            onChange: async (data: any) => {
              // console.log("oop");
              // console.log(data.raw);
              // 判断在 beforeUpload 中是否已经被阻止

              if (data.raw.type.startsWith("image/")) {
                const value = await fileToDataURL(data.raw);
                // 手动调用 renderField 的 onChange 回调把值传给表单
                onChange(value);
              }
            },
            onExceed: () => {
              alert("最多只能上传 1 个文件");
            },
            beforeUpload(file) {
              if (file.type.startsWith("image/")) {
                return true; // 允许上传视频
              } else {
                alert("只能上传图片文件");
                return false; // 禁止上传非视频文件
              }
            }
          },
          () => h(ElButton, () => "点击上传")
        )
      ]);
    }
  },
  {
    label: "电影",
    prop: "video",
    width: 100,
    valueType: "video",
    renderField(value, onChange) {
      // 自定义上传
      const handleHttpRequest = async ({ file, onError, onSuccess }: any) => {
        const { name } = file;
        fileName.value = name;
        // 计算文件的 MD5
        const fileMd5 = await calculateFileMd5(file);
        // 将计算出的 MD5 值赋值给 state.videoMd5
        state.value.videoMd5 = fileMd5;
        // 模拟检查文件是否已经上传
        await checkfile(fileMd5).then(response => {
          const { result } = response;
          if (result) {
            message("检查到独立文件，本网站已经存在相同的电影了", {
              type: "error"
            });
            uploadRef.value = false;
          }
        });
        if (!uploadRef.value) {
          console.log("阻止分块上传");
          return;
        }
        //开始分段上传
        const chunkSize = 5 * 1024 * 1024; // 每个分块大小为 5MB
        totalChunks.value = Math.ceil(file.size / chunkSize); // 总分块数
        let currentChunk = 0;
        // 上传每一块
        const dealChunk = async chunkIndex => {
          const start = chunkIndex * chunkSize;
          const end = Math.min(start + chunkSize, file.size);
          const chunk = file.slice(start, end);

          // 检查该分块是否已经上传
          const isUploaded = await checkChunkFile(fileMd5, chunkIndex);
          const { result } = isUploaded;
          if (result) {
            if (chunkIndex == totalChunks.value - 1) {
              message("本网站已经存在相同的电影了", { type: "error" });
              uploadRef.value = false;
            }
            return null;
          }

          // 上传当前分块
          try {
            await uploadFileChunk(chunk, chunkIndex, fileMd5);
          } catch (error) {
            console.error("分块上传失败", error);
            message("分块上传失败，请重试", { type: "error" });
            uploadRef.value = false; // 标记为上传失败
            throw error; // 抛出错误，跳过后续分块
          }
        };
        //分块上传
        for (let i = 0; i < totalChunks.value; i++) {
          await dealChunk(i);
          currentChunk++;
          // 可在这里添加上传进度条，反馈给用户上传状态
          percentage.value = parseFloat(
            ((currentChunk / totalChunks.value) * 100).toFixed(2)
          );
        }
        // 所有分块上传完成后进行合并操作
        if (uploadRef.value) {
          await mergechunks(
            state.value.videoMd5 + "",
            fileName.value,
            totalChunks.value
          );
        } else {
          console.error("文件上传未完成，无法合并分块。");
        }
        return file;
      };

      return h(Fragment, [
        // 这里假设使用 `ElVideo` 或者 `<video>` 标签来展示视频
        h(
          ElUpload,
          {
            action: "",
            limit: 1, // 限制上传文件数量为 1
            httpRequest: handleHttpRequest,
            onChange: async (data: any) => {
              //重置
              uploadRef.value = true;
              // 判断在 beforeUpload 中是否已经被阻止
              if (data.raw.type.startsWith("video/")) {
                const value = await fileToDataURL(data.raw);
                // 手动调用 renderField 的 onChange 回调把值传给表单
                onChange(value);
              }
            },
            onExceed: () => {
              message("最多只能上传 1 个文件", { type: "error" });
            },
            onRemove: () => {
              percentage.value = 0;
              onChange(null);
            },
            beforeUpload(file) {
              if (file.type.startsWith("video/")) {
                return true; // 允许上传视频
              } else {
                alert("只能上传视频文件");
                return false; // 禁止上传非视频文件
              }
            }
          },
          () => h(ElButton, () => "上传电影")
        ),
        // 显示上传进度条
        h(Progress1, {
          percentage: percentage.value,
          status: percentage.value === 100 ? "success" : "warning"
        })
      ]);
    }
  },
  {
    label: "描述",
    prop: "desc",
    valueType: "textarea",
    fieldProps: {
      maxlength: 200,
      showWordLimit: true,
      autosize: { minRows: 2, maxRows: 4 }
    }
  }
];

const handleSubmit = async (values: FieldValues) => {};
const dealSubmit = async (values: FieldValues) => {
  const check = await ruleFormRef.value.handleSubmit().then(res => {
    return res;
  });
  if (!check) {
    message("请填写完整信息", { type: "error" });
    return;
  }
  if (Array.isArray(values.quarter) && values.quarter[0] === "") {
    message("请选择档期", { type: "error" });
    return;
  }
  if (values.title == "新增") {
    if (
      values.video == "" ||
      values.video == undefined ||
      values.img == "" ||
      values.img == undefined
    ) {
      message("请上传媒资文件", { type: "error" });
      return;
    }
    if (!uploadRef.value) {
      console.log("走这里");
      message("请重新上传视频", { type: "error" });
      return;
    }
    if (percentage.value > 0 && percentage.value < 100) {
      console.log("走percentage" + percentage.value);
      return;
    }
  }
  if (typeof values.status === "string") {
    values.status =
      values.status === "上架"
        ? 1
        : values.status === "下架"
          ? 0
          : values.status;
  }
  return await saveOrUpdateMovie(values);
};
const handleSubmitError = (err: any) => {
  // console.log(err, "err");
};
const ruleFormRef = ref();
function getRef() {
  return ruleFormRef.value;
}
// 计算文件的 MD5
const calculateFileMd5 = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onloadend = () => {
      const arrayBuffer = reader.result as ArrayBuffer;
      const hash = md5(arrayBuffer); // 使用 md5 计算文件的 MD5
      resolve(hash);
    };

    reader.onerror = error => {
      reject(error);
    };

    reader.readAsArrayBuffer(file);
  });
};
const uploadFileChunk = async (
  file: File,
  chunkIndex: number,
  fileMd5: string
) => {
  try {
    const response = await uploadchunk(file, chunkIndex, fileMd5);
    // 在上传完成后处理响应
  } catch (error) {
    // 捕获上传错误
    console.error("Upload failed", error);
  }
};

defineExpose({ getRef, dealSubmit });
</script>

<template>
  <PlusForm
    ref="ruleFormRef"
    v-model="state"
    class="w-[450px] m-auto"
    :columns="columns"
    :rules="rules"
    :hasFooter="false"
    label-position="right"
    @submit="handleSubmit"
    @submit-error="handleSubmitError"
  >
  </PlusForm>
</template>
